"""
动作投影函数

将LLM的文本输出转换为环境可执行的动作字典
支持带记忆的推理模式
"""

import json
import re
from typing import Tuple, List, Dict


def meeting_projection(actions: List[str]) -> Tuple[List[Dict], List[int]]:
    """
    将LLM文本输出投影到会议调度动作

    预期格式：
    ```json
    {
        "action_type": "query_calendar" | "query_history" | "negotiate_time" | "select_time",
        "parameters": {
            # action_type对应的参数
        }
    }
    ```

    支持的动作类型：

    1. query_calendar - 查询日程
       {
           "action_type": "query_calendar",
           "parameters": {
               "persons": ["李明", "王芳"]
           }
       }

    2. query_history - 查询历史会议
       {
           "action_type": "query_history",
           "parameters": {}
       }

    3. negotiate_time - 协商时间
       {
           "action_type": "negotiate_time",
           "parameters": {
               "person": "李明",
               "day": "Monday",
               "time_slot": "afternoon"
           }
       }

    4. select_time - 选择并创建会议
       {
           "action_type": "select_time",
           "parameters": {
               "day": "Monday",
               "time_slot": "afternoon"
           }
       }

    参数:
        actions: LLM输出的文本列表

    返回:
        (action_dicts, valids): 动作字典列表和有效性标志列表
    """
    action_dicts = []
    valids = []

    for action_text in actions:
        valid = 1
        action_dict = {}

        # 尝试多种JSON提取模式
        patterns = [
            r'```json\s*(.*?)\s*```',  # ```json ... ```
            r'```\s*(.*?)\s*```',       # ``` ... ```
            r'\{[^{}]*"action_type"[^{}]*\}',  # 直接匹配JSON对象
        ]

        json_str = None
        for pattern in patterns:
            match = re.search(pattern, action_text, re.DOTALL)
            if match:
                json_str = match.group(1) if len(match.groups()) > 0 else match.group(0)
                break

        if json_str is None:
            # 没有找到JSON块，标记为无效
            valid = 0
            action_dicts.append({})
            valids.append(valid)
            continue

        # 解析JSON
        try:
            action_dict = json.loads(json_str)
        except json.JSONDecodeError:
            valid = 0
            action_dicts.append({})
            valids.append(valid)
            continue

        # 验证action_type字段
        if 'action_type' not in action_dict:
            valid = 0
        elif action_dict['action_type'] not in [
            'query_calendar', 'query_history', 'negotiate_time', 'select_time'
        ]:
            valid = 0

        # 验证parameters字段
        if valid and 'parameters' not in action_dict:
            valid = 0

        # 根据动作类型验证参数完整性
        if valid:
            action_type = action_dict['action_type']
            parameters = action_dict['parameters']

            if action_type == 'query_calendar':
                if 'persons' not in parameters or not isinstance(parameters['persons'], list):
                    valid = 0

            elif action_type == 'negotiate_time':
                required_fields = ['person', 'day', 'time_slot']
                if not all(field in parameters for field in required_fields):
                    valid = 0

            elif action_type == 'select_time':
                required_fields = ['day', 'time_slot']
                if not all(field in parameters for field in required_fields):
                    valid = 0

            # query_history 不需要额外参数验证

        action_dicts.append(action_dict)
        valids.append(valid)

    return action_dicts, valids


def meeting_memory_projection(actions: List[str]) -> Tuple[List[Dict], List[int]]:
    """
    带记忆的动作投影函数

    预期格式：
    <think>推理过程...</think>
    <action>
    ```json
    {
        "action_type": "...",
        "parameters": {...}
    }
    ```
    </action>
    <memory>关键信息用于下一步...</memory>

    参数:
        actions: LLM输出的文本列表

    返回:
        (action_dicts, valids): 动作字典列表和有效性标志列表
                               action_dict包含额外字段：thinking, memory
    """
    action_dicts = []
    valids = []

    for action_text in actions:
        valid = 1
        action_dict = {}

        # 提取think, action, memory块
        think_pattern = r'<think>\s*(.*?)\s*</think>'
        action_pattern = r'<action>\s*(.*?)\s*</action>'
        memory_pattern = r'<memory>\s*(.*?)\s*</memory>'

        think_match = re.search(think_pattern, action_text, re.DOTALL)
        action_match = re.search(action_pattern, action_text, re.DOTALL)
        memory_match = re.search(memory_pattern, action_text, re.DOTALL)

        # 提取thinking
        thinking = think_match.group(1).strip() if think_match else ""

        # 提取memory
        memory = memory_match.group(1).strip() if memory_match else ""

        # 提取action
        if action_match:
            action_content = action_match.group(1).strip()

            # 从action块中提取JSON
            base_action_dicts, base_valids = meeting_projection([action_content])

            if base_valids[0] == 1:
                action_dict = base_action_dicts[0]
                action_dict['thinking'] = thinking
                action_dict['memory'] = memory
            else:
                valid = 0
        else:
            # 如果没有<action>标签，尝试直接解析整个文本
            base_action_dicts, base_valids = meeting_projection([action_text])
            if base_valids[0] == 1:
                action_dict = base_action_dicts[0]
                action_dict['thinking'] = thinking
                action_dict['memory'] = memory
            else:
                valid = 0

        action_dicts.append(action_dict)
        valids.append(valid)

    return action_dicts, valids


def test_projection():
    """测试投影函数"""
    print("=== 测试基础投影函数 ===\n")

    # 测试1: query_calendar
    test1 = '''
    根据用户需求，我需要先查询所有参会人员的日程。
    ```json
    {
        "action_type": "query_calendar",
        "parameters": {
            "persons": ["李明", "王芳", "陈静"]
        }
    }
    ```
    '''
    dicts, valids = meeting_projection([test1])
    print(f"测试1 - query_calendar")
    print(f"  Valid: {valids[0]}")
    print(f"  Action: {dicts[0]}\n")

    # 测试2: query_history
    test2 = '''
    接下来查询历史会议模式。
    ```json
    {
        "action_type": "query_history",
        "parameters": {}
    }
    ```
    '''
    dicts, valids = meeting_projection([test2])
    print(f"测试2 - query_history")
    print(f"  Valid: {valids[0]}")
    print(f"  Action: {dicts[0]}\n")

    # 测试3: negotiate_time
    test3 = '''
    发现李明在周一下午不可用,需要协商。
    ```json
    {
        "action_type": "negotiate_time",
        "parameters": {
            "person": "李明",
            "day": "Monday",
            "time_slot": "afternoon"
        }
    }
    ```
    '''
    dicts, valids = meeting_projection([test3])
    print(f"测试3 - negotiate_time")
    print(f"  Valid: {valids[0]}")
    print(f"  Action: {dicts[0]}\n")

    # 测试4: select_time
    test4 = '''
    综合考虑后,选择周一下午作为会议时间。
    ```json
    {
        "action_type": "select_time",
        "parameters": {
            "day": "Monday",
            "time_slot": "afternoon"
        }
    }
    ```
    '''
    dicts, valids = meeting_projection([test4])
    print(f"测试4 - select_time")
    print(f"  Valid: {valids[0]}")
    print(f"  Action: {dicts[0]}\n")

    # 测试5: 无效格式
    test5 = "这是一个无效的输出，没有JSON格式"
    dicts, valids = meeting_projection([test5])
    print(f"测试5 - 无效格式")
    print(f"  Valid: {valids[0]}")
    print(f"  Action: {dicts[0]}\n")

    print("\n=== 测试带记忆的投影函数 ===\n")

    # 测试6: 带记忆的完整格式
    test6 = '''
    <think>
    根据需求，必选人员是李明和王芳，可选人员有陈静、刘强、赵敏。
    我需要先查询所有人的日程来找出可用时间。
    </think>
    <action>
    ```json
    {
        "action_type": "query_calendar",
        "parameters": {
            "persons": ["李明", "王芳", "陈静", "刘强", "赵敏"]
        }
    }
    ```
    </action>
    <memory>
    已查询5人日程，下一步需要查询历史会议模式以确定偏好时间。
    </memory>
    '''
    dicts, valids = meeting_memory_projection([test6])
    print(f"测试6 - 带记忆格式")
    print(f"  Valid: {valids[0]}")
    print(f"  Thinking: {dicts[0].get('thinking', '')[:50]}...")
    print(f"  Action Type: {dicts[0].get('action_type')}")
    print(f"  Memory: {dicts[0].get('memory', '')[:50]}...\n")


if __name__ == '__main__':
    test_projection()
